package com.leon.learnenginespace.drools.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.leon.learnenginespace.drools.utils.calculate.ICalculateBases;
import com.leon.learnenginespace.drools.utils.operation.IOperationBase;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 运算工具类
 *
 */

@Slf4j
@Configuration
public class OperationUtils {
    /**
     * 规则运算集合
     */
    private static Map<String, IOperationBase> operationBases;
    /**
     * 词条计算集合
     */
    private static Map<String, ICalculateBases> calculateBases;

    @Autowired
    public void setCalculate(Map<String, ICalculateBases> calculateBases) {
        OperationUtils.calculateBases = calculateBases;
    }
    @Autowired
    public void setOperationBasesBases(Map<String, IOperationBase> operationBases) {
        OperationUtils.operationBases = operationBases;
    }

    /**
     * 2对象运算公共方法
     * @param v1	值1
     * @param v2	值2
     * @param operationType	运算类型
     * @param dataType		数据类型
     * @return
     */
    public static Boolean operationTowValue(Object v1, Object v2, String operationType, String dataType) {
        return operation(operationType, dataType, new Object[]{v1, v2});

    }

    /**
     * 单对象运算
     * @param obj	值
     * @param operationType	运算类型
     * @param dataType		数据类型
     * @return
     */
    public static boolean singleOperation(Object obj, String operationType, String dataType) {
        return operation(operationType, dataType, obj);
    }

    /**
     * 运算
     *
     * @param operationType 运算类型
     * @param dataType      数据类型
     * @param objs 值数组
     * @return
     */
    private static Boolean operation(String operationType, String dataType, Object... objs) {
        IOperationBase modelBase = operationBases.get(operationType);
        return modelBase.operation(dataType, objs);
    }



    /**
     * 单词条运算
     * @param filedPath	词条路径
     * @param body		数据对象
     * @param value		阀值
     * @param operationType 运算类型
     * @param dataType	数据类型
     * @param paramNum	参数个数
     * @return
     */
    public static Boolean operation(String filedPath, JSONObject body, String value, String operationType, String dataType, String paramNum) {
        if (body == null) {
            log.warn("词条不完整");
            throw new FieldException("词条不完整");
        }
        if (StringUtils.isEmpty(filedPath)) {
            log.warn("词条路径为空");
            throw new FieldException("词条路径为空");
        }
        try {
            String[] paths = RuleCoverJsonUtils.getStringArray(filedPath);
            int size = paths.length;
            Object v = valueToV(value, operationType);
            boolean isArray = false;
            boolean isLeafNode = false;
            String key = null;
            String getKey = null;
            boolean isSupperArray = false;
            JSON superJson = body;
            for (int i = 0; i < size; i++) {

                isLeafNode = (i + 1 == size);
                key = paths[i];
                isArray = RuleCoverJsonUtils.getIsArray(key);
                getKey = RuleCoverJsonUtils.getPutKey(key, isArray);
                if (isLeafNode) {
                    return leafNode(isArray, superJson, operationType, dataType, getKey, v, null , null, null, false, false, paramNum, 1, false, null);
                }
                if (isArray) {
                    return RuleCoverJsonUtils.superJsonArrayProcess( isArray,  getKey,  superJson, i,  size, paths,  value,  operationType, dataType,isSupperArray,paramNum);
                } else {
                    superJson = RuleCoverJsonUtils.superJsonProcess(isArray,getKey, superJson);
                    isSupperArray = false;
                }
            }
        } catch (NullPointerException e) {
            throw new FieldException("词条路径为空");
        } catch (SuccessException e) {
            return true;
        }
        return false;
    }
    /**
     * 处理isResult
     * @param isResult
     * @throws SuccessException
     */
    private static void toIsReuslt(boolean isResult) throws SuccessException{
        if(isResult) {
            throw new SuccessException("触发规则");
        }
    }

    /**
     * value转换
     * @param value
     * @param operationType
     * @return
     */
    private static Object valueToV(String value, String operationType) {
        Object v = value;
        if ("containsOperation".equals(operationType)) {
            v = Arrays.asList(value.split(","));
        }
        return v;
    }
    /**
     * 叶子节点
     * @param isArray	是否是数据节点
     * @param superJson	父级节点
     * @param operationType	运算类型
     * @param dataType	数据类型
     * @param getKey	获取数据key
     * @param v			阀值
     * @param singleValue	数据对象中值
     * @param mathOperator	计算类型
     * @param mathDataType	计算值数据类型
     * @param isCalculate	是否计算
     * @param isSuperArray	父级是不是数组
     * @param paramNum	参数个数
     * @param isType	标记多词条时，那个词条不是数组
     * @param isSameLevelArray	是否是同级数组
     * @param leafNodeName	叶子节点词条名称
     * @return
     * @throws SuccessException
     */
    private static boolean leafNode(boolean isArray, JSON superJson, String operationType, String dataType, String getKey, Object v, String singleValue, String mathOperator, String mathDataType, boolean isCalculate, boolean isSuperArray, String paramNum, int isType, boolean isSameLevelArray, String leafNodeName) throws SuccessException{
        String filedValue = null;
        boolean isResult = false;
        JSONArray superJsonArray = null;
        Object paramObj = null;
        if(isArray) {
            superJsonArray = (JSONArray) superJson;
            int size = superJsonArray.size();
            for (int j = 0; j < size; j ++) {
                filedValue = superJsonArray.getString(j);
                paramObj = getParamObj(isCalculate, mathOperator, singleValue, filedValue, mathDataType, isType);
                isResult = processRule(paramNum, paramObj, v, operationType, dataType);
                toIsReuslt(isResult);
            }
        } else {
            JSONObject superJsonObject = null;
            if(isSuperArray) {
                superJsonArray = (JSONArray) superJson;
                for (int j = 0; j < superJsonArray.size(); j ++) {
                    superJsonObject = superJsonArray.getJSONObject(j);
                    filedValue = superJsonObject.getString(getKey);
                    if(!isSameLevelArray) {
                        paramObj = getParamObj(isCalculate, mathOperator, singleValue, filedValue, mathDataType, isType);
                    }else {
                        singleValue = superJsonObject.getString(leafNodeName);
                        paramObj = getParamObj(isCalculate, mathOperator, singleValue, filedValue, mathDataType, isType);
                    }
                    isResult = processRule(paramNum, paramObj, v, operationType, dataType);
                    toIsReuslt(isResult);
                }
            } else {
                superJsonObject = (JSONObject) superJson;
                filedValue = superJsonObject.getString(getKey);
                paramObj = getParamObj(isCalculate, mathOperator, singleValue, filedValue, mathDataType, isType);
                isResult = processRule(paramNum, paramObj, v, operationType, dataType);
            }
        }
        return isResult;
    }

    /**
     *  执行规则
     * @param paramNum 参数个数
     * @param paramObj 数据对象中值
     * @param v 阀值
     * @param operationType 运算类型
     * @param dataType 数据类型
     * @return
     */
    private static boolean processRule(String paramNum,Object paramObj, Object v, String operationType, String dataType) {
        boolean isResult = false;
        if("1".equals(paramNum)) {
            isResult = OperationUtils.singleOperation(paramObj, operationType, dataType);
        }else {
            isResult = OperationUtils.operationTowValue( paramObj,v, operationType, dataType);
        }
        return isResult;
    }

    /**
     * 获取参数
     * @param isCalculate 是否计算
     * @param mathOperator	计算类型
     * @param mathDataType	计算值数据类型
     * @param singleValue	数据对象中值
     * @param filedValue  阀值
     * @param isType 标记多词条时，那个词条不是数组
     * @return
     */
    private static Object getParamObj(boolean isCalculate, String mathOperator, String singleValue, String filedValue,String mathDataType, int isType) {
        Object paramObj = null;
        if(isCalculate){
            ICalculateBases calculate = calculateBases.get(mathOperator);
            if(calculate == null) {
                throw new FieldException("计算类型错误");
            }
            if(1 == isType) {
                paramObj = calculate.cal(singleValue, filedValue, mathDataType);
            } else {
                paramObj = calculate.cal(filedValue, singleValue, mathDataType);
            }

        }else {
            paramObj = filedValue;
        }

        return paramObj;
    }
    /**
     * 计算运算方法
     * @param filedPath	词条1
     * @param filedPath2	词条2
     * @param mathOperator	计算类型
     * @param mathDataType	计算值数据类型
     * @param bodyArray	数组对象
     * @param body	原对象
     * @param value 阀值
     * @param operationType 运 算类型
     * @param dataType 数据类型
     * @return
     * @throws SuccessException
     */
    private static Boolean operation(String filedPath, String filedPath2, String mathOperator,String mathDataType,JSONArray bodyArray,JSONObject body, String value, String operationType, String dataType) throws SuccessException {
        String singleValue = null;
        int isType =  1;
        boolean isSameLevelArray = false;
        JSONObject jsonBody = null;
        boolean isResult = false;
        int jsonArraySize = bodyArray.size();
        if(filedPath.indexOf("#") != -1 && filedPath2.indexOf("#") != -1){
            //增加逻辑
            isSameLevelArray = false;
            for (int i = 0; i < jsonArraySize; i ++) {
                jsonBody = bodyArray.getJSONObject(i);
                JSONArray jsonArray = RuleCoverJsonUtils.getArrayNode(filedPath, jsonBody);
                String tempPath = RuleCoverJsonUtils.getArrayNodeSubKey(filedPath);
                isResult = operation(tempPath,  filedPath2,  mathOperator, mathDataType, jsonArray, body,  value,  operationType,  dataType);
                toIsReuslt(isResult);
            }
            return isResult;
        } else {
            Object v = value;
            if ("containsOperation".equals(operationType)) {
                v = Arrays.asList(value.split(","));
            }
            int size = 0;
            boolean isSuperArray = false;
            String[] paths = null;
            Map<String, Object> mapJson = new HashMap<>();
            for (int i = 0; i < jsonArraySize; i ++) {
                jsonBody = bodyArray.getJSONObject(i);
                singleValue = RuleCoverJsonUtils.getNodeValue(filedPath, jsonBody);
                paths = RuleCoverJsonUtils.getStringArray(filedPath2);
                //isType =  1;
                JSON superJson = body;
                size = paths.length;
                mapJson.put("superJson", superJson);
                for (int j = 0; j < size; j++) {
                    String key = paths[j];
                    isResult = processMidJsonObject( j, size, paths, mapJson, operationType, dataType, v, singleValue, mathOperator,  mathDataType, isType, isSameLevelArray, isSuperArray, key);
                    toIsReuslt(isResult);
                    superJson = (JSON) mapJson.get("superJson");
                    isSuperArray = (Boolean)mapJson.get("isSuperArray");
                }
            }
        }
        return isResult;
    }
    /**
     * 父级是否是数组
     * @param isArray
     * @param paramMap
     */
    private static void isSuperArray(boolean isArray, Map<String, Object> paramMap) {
        paramMap.put("isSuperArray", isArray);
    }
    /**
     * 处理中间节点，jsonobject
     * @param j
     * @param size
     * @param paths
     * @param mapJson
     * @param operationType
     * @param dataType
     * @param v
     * @param singleValue
     * @param mathOperator
     * @param mathDataType
     * @param isType
     * @param isSameLevelArray
     * @param isSupperArray
     * @param key
     * @return
     * @throws SuccessException
     */
    private static Boolean processMidJsonObject(int j, int size, String[] paths, Map<String, Object> mapJson, String operationType, String dataType, Object v, String singleValue,String mathOperator, String mathDataType, int isType,boolean  isSameLevelArray, boolean isSupperArray, String key) throws SuccessException {
        boolean isLeafNode = (j + 1 == size);
        JSON superJson = (JSON) mapJson.get("superJson");
        boolean isArray = RuleCoverJsonUtils.getIsArray(key);
        String getKey =  RuleCoverJsonUtils.getPutKey(key, isArray);
        if (isLeafNode) {
            return leafNode(isArray, superJson, operationType, dataType, getKey, v, singleValue, mathOperator, mathDataType, true,isSupperArray, "2", isType, isSameLevelArray, null);
        }
        if (isSupperArray) {
            return superJsonArrayProcess(isArray, superJson, operationType, dataType, getKey, v, singleValue, mathOperator, mathDataType, true,true, "2", isType, isSameLevelArray, null, j, paths, size);
        } else {
            superJson = RuleCoverJsonUtils.superJsonProcess(isArray, getKey, superJson);

        }
        isSuperArray(isArray, mapJson);
        mapJson.put("superJson", superJson);
        return false;
    }
    /**
     * 处理数组，父级同样是数组
     * @param isArray
     * @param superJson
     * @param operationType
     * @param dataType
     * @param getKey
     * @param v
     * @param singleValue
     * @param mathOperator
     * @param mathDataType
     * @param isCalculate
     * @param isSuperArray
     * @param paramNum
     * @param isType
     * @param isSameLevelArray
     * @param leafNodeName
     * @param i
     * @param paths
     * @param size
     * @return
     * @throws SuccessException
     */
    private static Boolean superJsonArrayProcess(boolean isArray, JSON superJson, String operationType, String dataType, String getKey, Object v, String singleValue, String mathOperator, String mathDataType, boolean isCalculate, boolean isSuperArray, String paramNum, int isType, boolean isSameLevelArray, String leafNodeName, int i, String[] paths, int size) throws SuccessException {
        JSONArray superJsonArray = null;
        int arrayLength = 0;
        if(isSuperArray) {
            superJsonArray = (JSONArray) superJson;
        } else {
            JSONObject superJsonObject = (JSONObject) superJson;
            superJsonArray = superJsonObject.getJSONArray(getKey);
        }
        arrayLength = superJsonArray.size();
        boolean isResult = false;
        JSONArray tempJsonArray = null;
        if (isArray) {
            String tempKey = paths[i+1];
            String tempFiled = RuleCoverJsonUtils.getParamKey(i+1, size, paths);
            String[] tempPaths = RuleCoverJsonUtils.getStringArray(tempFiled);
            int tempSize = tempPaths.length;
            Map<String, Object> mapJson = new HashMap<>();
            for (int j = 0; j < arrayLength; j++) {
                isArray = RuleCoverJsonUtils.getIsArray(tempKey);
                superJson = isArray? superJsonArray.getJSONArray(j):superJsonArray.getJSONObject(j);
                getKey = RuleCoverJsonUtils.getPutKey(tempKey, isArray);
                if(isArray) {
                    tempJsonArray = (JSONArray) superJson;
                    for(int k = 0; k < tempJsonArray.size(); k ++) {
                        isResult = superJsonArrayProcess( isArray,  tempJsonArray.getJSONArray(k),  operationType,  dataType,  getKey, v,  singleValue,  mathOperator,  mathDataType,  isCalculate,  isSuperArray,  paramNum,  isType,  isSameLevelArray,  leafNodeName,  i, paths,  size) ;
                        toIsReuslt(isResult);
                    }
                } else {
                    JSONObject json = (JSONObject) superJson;
                    tempJsonArray = json.getJSONArray(getKey);
                    String key = null;
                    for(int k = 0; k < tempJsonArray.size(); k ++) {
                        isSuperArray = false;
                        for(int l =0; l < tempSize; l++ ) {
                            key = tempPaths[l];
                            mapJson.put("superJson", tempJsonArray.getJSONObject(k));
                            isResult = processMidJsonObject(l, tempSize, tempPaths, mapJson , operationType, dataType, v,  singleValue, mathOperator,  mathDataType,  isType,  isSameLevelArray,  isSuperArray, key);
                            toIsReuslt(isResult);
                            isSuperArray = (Boolean)mapJson.get("isSuperArray");
                        }
                    }
                }
                toIsReuslt(isResult);
            }
        } else  {
            for (int j = 0; j < arrayLength; j++) {
                isResult =  leafNode(isArray, superJson, operationType, dataType, getKey, v, singleValue, mathOperator, mathDataType, true,true, "2", isType, isSameLevelArray, null);
                toIsReuslt(isResult);
            }
        }
        return isResult;
    }
    /**
     * 计算运算方法
     * @param filedPath	词条1
     * @param filedPath2	词条2
     * @param mathOperator	计算类型
     * @param mathDataType	计算值数据类型
     * @param body	数据对象
     * @param value 阀值
     * @param operationType 运 算类型
     * @param dataType 数据类型
     * @return
     */
    public static Boolean operation(String filedPath, String filedPath2, String mathOperator,String mathDataType,JSONObject body, String value, String operationType, String dataType) {
       /* String singleValue = null;
        String calFiledPath = null;
        int isType =  2;
        boolean isSameLevelArray = false;
        String leafNodeName = null;*/
        Map<String, Object> paramMap = new HashMap<>();
        try {
            boolean isOver = processFiledArray(filedPath, filedPath2, mathOperator, mathDataType, body, value, operationType, dataType, paramMap);
            if(isOver) {
                return false;
            }
            String calFiledPath = (String) paramMap.get("calFiledPath");
            Integer isType = (Integer) paramMap.get("isType");
            String singleValue = (String) paramMap.get("singleValue");
            String leafNodeName = (String) paramMap.get("leafNodeName");
            Boolean isSameLevelArray = (Boolean) paramMap.get("isSameLevelArray");
            String[] paths = RuleCoverJsonUtils.getStringArray(calFiledPath);
            int size = paths.length;
            Object v = valueToV(value, operationType);
            boolean isArray = false;
            boolean isLeafNode = false;
            String key = null;
            String getKey = null;
            boolean isSupperArray = false;
            JSON superJson = body;
            for (int i = 0; i < size; i++) {
                isLeafNode = (i + 1 == size);
                key = paths[i];
                isArray = RuleCoverJsonUtils.getIsArray(key);
                getKey = RuleCoverJsonUtils.getPutKey(key, isArray);
                if (isLeafNode) {
                    return leafNode(isArray, superJson, operationType, dataType, getKey, v, singleValue, mathOperator, mathDataType, true,true, "2", isType, isSameLevelArray, leafNodeName);
                }
                if (isSupperArray) {
                    return RuleCoverJsonUtils.superJsonArrayProcess( isArray, getKey, superJson, i, size, paths,  value,  operationType, dataType,isSupperArray,"2");
                } else {
                    superJson = RuleCoverJsonUtils.superJsonProcess(isArray,getKey, superJson);
                    isSupperArray = false;
                }
            }
        } catch (SuccessException e) {
            return true;
        }
        return false;
    }
    /**
     * 处理词条数组
     * @param filedPath
     * @param filedPath2
     * @param mathOperator
     * @param mathDataType
     * @param body
     * @param value
     * @param operationType
     * @param dataType
     * @param paramMap
     * @return
     * @throws SuccessException
     */
    private static boolean processFiledArray(String filedPath, String filedPath2, String mathOperator, String mathDataType, JSONObject body, String value,  String operationType,  String dataType, Map<String, Object> paramMap) throws SuccessException {
        int isType = 2;
        String calFiledPath = null;
        String leafNodeName = null;
        String singleValue = null;
        boolean isSameLevelArray = false;
        // 两词条都是数组
        if(filedPath.indexOf("#") != -1 && filedPath2.indexOf("#") != -1) {
            String notLeadNodeFiledPath = RuleCoverJsonUtils.getNotLeadNodeFiledPath(filedPath);
            String notLeadNodeFiledPath2 = RuleCoverJsonUtils.getNotLeadNodeFiledPath(filedPath2);
            isType =  1;
            //两词条处叶子节点外，其它节点一致
            if(notLeadNodeFiledPath.equals(notLeadNodeFiledPath2)) {
                isSameLevelArray = true;
                calFiledPath = filedPath;
                leafNodeName =  RuleCoverJsonUtils.getLeadNodeFiledName(filedPath2);
            } else {
                //两词条都是数组,节点不一致
                //增加逻辑
                isSameLevelArray = false;
                JSONArray jsonArray = RuleCoverJsonUtils.getArrayNode(filedPath, body);
                String tempPath = RuleCoverJsonUtils.getArrayNodeSubKey(filedPath);
                operation(tempPath,  filedPath2,  mathOperator, mathDataType, jsonArray, body,  value,  operationType,  dataType);
                return true;
            }
        } else {
            //词条1是数组
            if(filedPath.indexOf("#") == -1) {
                singleValue = RuleCoverJsonUtils.getNodeValue(filedPath,body);
                calFiledPath = filedPath2;
                isType =  1;
            }
            //词条2是数组
            if(filedPath2.indexOf("#") == -1 ){
                singleValue = RuleCoverJsonUtils.getNodeValue(filedPath2, body);
                calFiledPath = filedPath;
                isType =  2;
            }
        }
        paramMap.put("isType", isType);
        paramMap.put("calFiledPath", calFiledPath);
        paramMap.put("leafNodeName", leafNodeName);
        paramMap.put("singleValue", singleValue);
        paramMap.put("isSameLevelArray", isSameLevelArray);
        return false;
    }
    public static void main(String[] args) {

        //String aa = "aa.aa.aa";//OperationUtils.
        String aa = "aa.aa.bb";//OperationUtils.
        int aaIndex =aa.lastIndexOf(".");
        System.out.println(aaIndex);
        System.out.println(aa.substring(aaIndex + 1));
    }
}

